/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package skyproc;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Objects;
import java.util.zip.DataFormatException;
import lev.LExporter;
import lev.LFlags;
import lev.LStream;
import skyproc.exceptions.BadParameter;
import skyproc.exceptions.BadRecord;

/**
 *
 * @author Justin Swanson
 */
public class AMMO extends MajorRecordDescription {

    static Type[] types = {Type.AMMO};
    SubData OBND = new SubData(Type.OBND);
    SubString MODL = new SubString(Type.MODL, true);
    SubData MODT = new SubData(Type.MODT);
    SubForm YNAM = new SubForm(Type.YNAM);
    SubForm ZNAM = new SubForm(Type.ZNAM);
    /**
     *
     */
    public KeywordSet keywords = new KeywordSet();
    DATA DATA = new DATA();

    AMMO() {
	super();
	subRecords.remove(Type.FULL);
	subRecords.remove(Type.DESC);

	subRecords.add(OBND);
	subRecords.add(FULL);
	subRecords.add(MODL);
	subRecords.add(MODT);
	subRecords.add(YNAM);
	subRecords.add(ZNAM);
	subRecords.add(description);
	subRecords.add(keywords);
	subRecords.add(DATA);
    }

    @Override
    Record getNew() {
	return new AMMO();
    }

    @Override
    Type[] getTypes() {
	return types;
    }

    class DATA extends SubRecord {

	FormID projectile = new FormID();
	LFlags flags = new LFlags(4);
	float damage = 0;
	int value = 0;

	DATA() {
	    super(Type.DATA);
	}

	@Override
	void export(LExporter out, Mod srcMod) throws IOException {
	    super.export(out, srcMod);
	    projectile.export(out);
	    out.write(flags.export(), 4);
	    out.write(damage);
	    out.write(value);
	}

	@Override
	void parseData(LStream in) throws BadRecord, DataFormatException, BadParameter, IOException {
	    super.parseData(in);
	    projectile.setInternal(in.extract(4));
	    flags.set(in.extract(4));
	    damage = in.extractFloat();
	    value = in.extractInt(4);
	}

	@Override
	SubRecord getNew(Type type) {
	    return new DATA();
	}

	@Override
	int getContentLength(Mod srcMod) {
	    return 16;
	}

	@Override
	ArrayList<FormID> allFormIDs() {
	    ArrayList<FormID> out = new ArrayList<FormID>(1);
	    out.add(projectile);
	    return out;
	}
        
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final DATA other = (DATA) obj;
            if (!Objects.equals(this.projectile, other.projectile)) {
                return false;
            }
            if (!Objects.equals(this.flags, other.flags)) {
                return false;
            }
            if (Float.floatToIntBits(this.damage) != Float.floatToIntBits(other.damage)) {
                return false;
            }
            if (this.value != other.value) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 89 * hash + Objects.hashCode(this.projectile);
            hash = 89 * hash + Objects.hashCode(this.flags);
            hash = 89 * hash + Float.floatToIntBits(this.damage);
            hash = 89 * hash + this.value;
            return hash;
        }

        @Override
        public SubRecord merge(SubRecord no, SubRecord bo) {
            DATA d = this;
            if (!(no == null && bo == null && getClass() != no.getClass() && getClass() != bo.getClass())) {
                final DATA nd = (DATA) no;
                final DATA bd = (DATA) bo;
                d.projectile.merge(nd.projectile, bd.projectile, type[0]);
                SkyBash.merge(d.damage, nd.damage, bd.damage, type[0], "damage");
                SkyBash.merge(d.value, nd.value, bd.value, type[0], "value");
                d.flags.merge(nd.flags, bd.flags, type[0]);
            }
            return d;
        }
    }

    /**
     *
     */
    public enum AMMOFlag {

	/**
	 *
	 */
	IgnoresWeaponResistance,
	/**
	 *
	 */
	VanishesWhenNotInFlight;
    }
    
    //Generics
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final AMMO other = (AMMO) obj;
        if (!Objects.equals(this.OBND, other.OBND)) {
            return false;
        }
        if (!Objects.equals(this.MODL, other.MODL)) {
            return false;
        }
        if (!Objects.equals(this.MODT, other.MODT)) {
            return false;
        }
        if (!Objects.equals(this.YNAM, other.YNAM)) {
            return false;
        }
        if (!Objects.equals(this.ZNAM, other.ZNAM)) {
            return false;
        }
        if (!Objects.equals(this.keywords, other.keywords)) {
            return false;
        }
        if (!Objects.equals(this.DATA, other.DATA)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 29 * hash + Objects.hashCode(this.OBND);
        hash = 29 * hash + Objects.hashCode(this.MODL);
        hash = 29 * hash + Objects.hashCode(this.MODT);
        hash = 29 * hash + Objects.hashCode(this.YNAM);
        hash = 29 * hash + Objects.hashCode(this.ZNAM);
        hash = 29 * hash + Objects.hashCode(this.keywords);
        hash = 29 * hash + Objects.hashCode(this.DATA);
        return hash;
    }

    //SkyBash merger
    @Override
    public MajorRecord merge(MajorRecord no, MajorRecord bo) {
        super.merge(no, bo);
        AMMO a = this;
        if (!(no == null && bo == null && (no instanceof AMMO) && (bo instanceof AMMO))) {
            final AMMO na = (AMMO) no;
            final AMMO ba = (AMMO) bo;
            a.DATA.merge(na.DATA, ba.DATA);
            a.MODL.merge(na.MODL, ba.MODL);
            a.MODT.merge(na.MODT, ba.MODT);
            a.YNAM.merge(na.YNAM, ba.YNAM);
            a.ZNAM.merge(na.ZNAM, ba.ZNAM);
            a.keywords.merge(na.keywords, ba.keywords);
            a.OBND.merge(na.OBND, ba.OBND);
        }
        return a;
    }

    //Get/Set
    /**
     *
     * @param path
     */
    public void setModel(String path) {
	MODL.setString(path);
    }

    /**
     *
     * @return
     */
    public String getModel() {
	return MODL.print();
    }

    /**
     *
     * @param sound
     */
    public void setPickupSound(FormID sound) {
	YNAM.setForm(sound);
    }

    /**
     *
     * @return
     */
    public FormID getPickupSound() {
	return YNAM.getForm();
    }

    /**
     *
     * @param sound
     */
    public void setDropSound(FormID sound) {
	ZNAM.setForm(sound);
    }

    /**
     *
     * @return
     */
    public FormID getDropSound() {
	return ZNAM.getForm();
    }

    /**
     *
     * @param projectile
     */
    public void setProjectile(FormID projectile) {
	DATA.projectile = projectile;
    }

    /**
     *
     * @return
     */
    public FormID getProjectile() {
	return DATA.projectile;
    }

    /**
     *
     * @param flag
     * @param on
     */
    public void set(AMMOFlag flag, boolean on) {
	DATA.flags.set(flag.ordinal() + 1, on);
    }

    /**
     *
     * @param flag
     * @return
     */
    public boolean get(AMMOFlag flag) {
	return DATA.flags.get(flag.ordinal() + 1);
    }

    /**
     *
     * @param damage
     */
    public void setDamage(float damage) {
	DATA.damage = damage;
    }

    /**
     *
     * @return
     */
    public float getDamage() {
	return DATA.damage;
    }

    /**
     *
     * @param gold
     */
    public void setValue(int gold) {
	DATA.value = gold;
    }

    /**
     *
     * @return
     */
    public int getValue() {
	return DATA.value;
    }
}
